package Server;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Date;
import java.util.Queue;
import java.util.Vector;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import InetAgreement.InetDataEncapsulation;
import Tools.Log;
import XML.XML;
import XML.XMLNode;

/**
 * ----客户线程----
 * 
 * ClientThread(....);//创建方法
 * 
 * @author Administrator
 * 
 */
public class ClientThread extends Thread {
	public static final String LAN_NET = "LAN"; // 内网
	public static final String OUTER_NET = "Outer net"; // 外网
	private static ExecutorService exeService = Executors.newCachedThreadPool();

	protected final Server s; // 服务端
	private Queue<Object> messages; // 返回数据队列
	private XML logincmd = null;
	protected final Socket client;
	private BufferedReader in;
	private PrintWriter out;
	private InetDataEncapsulation dp; // 数据封包对象
	private Thread sendT; // 发送数据线程
	private int speed_Net; // 通讯速度
	private boolean isOuterNet; // 外网/内网
	long size = 0; // 统计传输流量
	long time = 0; // 统计传输时间
	long lasttime; // 最后通信事件

	public ClientThread(final Socket client, Server s) throws IOException {
		this.client = client;
		this.s = s;
		
		init();
	}

	protected void init() throws IOException {
		dp = new InetDataEncapsulation();// 数据封包对象
		initStream();
		messages = new ConcurrentLinkedQueue<Object>();
		sendT = new Thread() {

			@Override
			public void run() {
				try {
					while (sendT != null) {

						Date start = new Date();// 记录传输前的时间

						while (!messages.isEmpty()) {
							Object data = messages.poll();
							
							sendImpl(data);
							
						}

						time += (new Date().getTime() - start.getTime());// 统计传输数据消耗时间

						// 超市断开连接
						if (lasttime > 0 && System.currentTimeMillis() - lasttime > 60000) {
							close();
						}
						Thread.sleep(1000);

					}
				} catch (Exception e) {
					try {
						client.close();
					} catch (IOException e1) {
						e1.printStackTrace();
					}
					e.printStackTrace();
					Log.print(client.getInetAddress() + " SendThread:Exception");
				}
			}
		};
		start(); // 启动数据监听线程
		sendT.start(); // 启动数据发送线程
	}

	protected void sendImpl(Object data) {
		if(data instanceof String){
			String str = (String) data;
			size += str.length();// 统计流量
			out.println(str);
			out.flush();// 发送缓存数据
			
			if (logincmd != null) {
				Log.print("[ClientThread]S>C:" + ClientThread.this.getName() + "\tData:" + (str.length()<1024?str:str.substring(0, str.indexOf(">", 1))));
			}
		}
	}

	protected void initStream() throws IOException {
		in = new BufferedReader(new InputStreamReader(client.getInputStream()));
		out = new PrintWriter(client.getOutputStream(), true);
	}

	/**
	 * 用户请求指令处理函数
	 * 
	 * @param cmd
	 */
	public void actCmd(XML cmd) {
		Vector<XMLNode> alcmd = new Vector<XMLNode>(0);
		cmd.getList(null, alcmd, false); // 取命令列表
		XMLNode xf;
		XML CMD;

		// /////////遍历指令集////////////
		while (alcmd.size() > 0) {
			xf = alcmd.remove(0);
			CMD = cmd.remove(xf);
			CMD.copy(xf);// 设置住命令
			s.informEvent(new ClientRequestEvent(s, this, CMD)); // 触发请求事件
		}
		// ///////////////////////////////
	}

	/**
	 * 关闭客户线程
	 */
	public void close() {
		try {
			sendT = null;// 让发送数据线程结束
			if (client != null){
				client.close();// 关闭连接后会自动从服务端线程集合中移除
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	public XML getLogincmd() {
		return logincmd;
	}

	public Socket getSocket() {
		return client;
	}

	public boolean isOuterNet() {
		return isOuterNet;
	}

	/**
	 * 数据监听线程
	 */
	@Override
	public void run() {
		try {
			// 监听数据流
			while (!client.isClosed() && client.isConnected()) {
				
				runReadNetBytes();
				
				try {// 延时休眠100毫秒
					Thread.sleep(100);
				} catch (InterruptedException e) {
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
			Log.print("Client:IOException: " + e.getMessage());

			s.informEvent(new ClientException(s, this, e));// 触发客户离开事件

		} finally {
			close(); // 关闭客户

			s.informEvent(new ClientExitEvent(s, this));// 触发客户离开事件

		}
	}

	protected void runReadNetBytes() throws IOException {
		StringBuffer line = new StringBuffer();
		String str = "";
		// 1、读取请求数据流
		str = in.readLine();
		if (str != null) {
			if (str.indexOf("pulse") == -1) {
				Log.print(new StringBuffer("[Client] " + client).append("  RecvLine: ").append(str.length()));
			}
			line.append(str);
			// 2、处理请求数据流
			while ((str = dp.baleBreaking(line)) != null) {// 解数据包
				if (str.indexOf("pulse") == -1) {
					Log.print(new StringBuffer("[Client] " + client).append("  RecvPack: ").append(str.length()<1024?str:str.substring(0,str.indexOf(">",1))));
				}
				final String xmlstr = str;
				exeService.execute(new Runnable() {
					@Override
					public void run() {
						XML cmd = new XML(xmlstr);// 解析被解包的xml数据
						actCmd(cmd);// 分解请求列表，并触发监听器
					}
				});
			}
		}
	}

	public void send(Object obj){
		messages.offer(obj);
	}
	/**
	 * 发送数据（封包指令后加入发送队列）
	 * 
	 * @param msg
	 */
	public void sendMessage(String msg) {
		send(dp.Package(msg));// 列入待发送队列
	}

	public void sendMessage(XMLNode msg) {
		sendMessage(msg.toString());
	}

	public void setLogincmd(XML logincmd) {
		this.logincmd = logincmd;
	}

	public void setOuterNet(boolean isOuterNet) {
		this.isOuterNet = isOuterNet;
	}

	@Override
	public String toString() {
		return "[ClientThread: name=" + getName() + " address=\"" + client.getInetAddress() + ":" + client.getPort() + "\"]";
	}

	public int getMessageCount() {
		return messages.size();
	}

	public void send(byte[] buf, int offset, int len) {
	}
}